//============================================================================
// Name        : ssw556_banking.cpp
// Author      : Mike Colina
// Version     :
// Copyright   :
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

#include "database.h"
#include "user.h"

////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void PrintSystemMenu()
{
	std::cout << "\n\n*********** SSW 556 Bank *********** " << std::endl;
	std::cout << "1. Login" 				 << std::endl;
	std::cout << "(-1 to Exit)" << std::endl << std::endl;
}

////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void PrintAuthenticatedUserMenu()
{
	std::cout << "*********** Account Main Menu *********** " << std::endl;
	std::cout << "1. View Balance" << std::endl;
	std::cout << "2. Transfer Funds" << std::endl;
	std::cout << "3. Logout" << std::endl << std::endl;
}

////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int GetMenuSelection()
{
	std::string inputString = "";
	std::cout << "Selection: ";
	std::cin >> inputString;

	int selection;
	std::istringstream istr(inputString);
	istr >> selection;

	return( selection );
}

////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void GetCredentials( std::string& username, std::string& password )
{
	std::cout << "Please enter username and password: " << std::endl;
	std::cout << "Username: ";
	cin >> username;
	std::cout << "Password: ";
	std::cin >> password;
	std::cout << std::endl;
}

int main()
{
	Database db;
  
  db.CreateCannedAccounts () ;
  db.CreateCannedUsers () ;
  
	int selection = -1;

	do
	{
		PrintSystemMenu();
		selection = GetMenuSelection();

		switch( selection )
		{
			case -1 :
				std::cout << "Exiting System" << std::endl;
				break;

			case 1 :
			{
				std::string username = "";
				std::string password = "";

				GetCredentials( username, password );
				unsigned int const userHandle = db.AuthenticateUser(username, password);
				if( userHandle != 0 )
				{
					do
					{
						PrintAuthenticatedUserMenu();
						selection = GetMenuSelection();
						switch( selection )
						{
							// View Balance
							case 1 :
                db.DisplayAccounts ( userHandle ) ;
								break;

							// Transfer Funds
							case 2 :
							{
								db.DisplayAccounts ( userHandle ) ;

								std::string fromAcct = "";
								std::cout << "Transfer From: ";
								std::cin >> fromAcct;

								std::string toAcct   = "";
								std::cout << "Transfer To: ";
								std::cin >> toAcct;

								std::string value 	 = "";
								std::cout << "Amount to Transfer: ";
								std::cin >> value;
								std::cout << std::endl;
								// First check for valid characters
								bool valid = true;
								for( unsigned int i = 0; i < value.size(); ++i )
								{
									// Valid if a number
									if( (value[i] >= '0') && (value[i] <= '9') )
									{
										continue;
									}

									// Valid if a decimal
									if( value[i] == '.' )
									{
										continue;
									}

									// If we got here, then the character is not valid
									valid = false;
									break;
								}

								// Next check if there are any decimals inputted, and if there
								// are, only 1
								unsigned int decCount = 0;
								if( valid )
								{
									for( unsigned int i = 0; i < value.size(); ++i )
									{
										if( value[i] == '.')
										{
											++decCount;
											if( decCount > 1 )
											{
												valid = false;
												break;
											}
										}
									}
								}

								if( valid && (decCount == 1) )
								{
									// We essentially want to make sure that the decimal (if used)
									// is located in the following locations:
									// Very last: Ex. 34.
									// 2nd to last: Ex. 34.1
									// 3rd to last: Ex. 34.12
									for( unsigned int i = 0; i < value.size(); ++i )
									{
										if( value[i] == '.')
										{
											if( i < (value.size() - 3) )
											{
												valid = false;
												break;
											}
										}
									}
								}
								double amt = 0;
								if( valid )
								{
									std::istringstream istr(value);
									istr >> amt;
								}

								// Validate from acct

								for( unsigned int i = 0; i < fromAcct.size(); ++i )
								{
									// Valid if a number
									if( (fromAcct[i] >= '0') && (fromAcct[i] <= '9') )
									{
										continue;
									}

									// If we got here, then the character is not valid
									valid = false;
									break;
								}
								uint32_t fromAcctID = 0;
								if( valid )
								{
									std::istringstream istr(fromAcct);
									istr >> fromAcctID;
								}

								// Validate to acct
								for( unsigned int i = 0; i < toAcct.size(); ++i )
								{
									// Valid if a number
									if( (toAcct[i] >= '0') && (toAcct[i] <= '9') )
									{
										continue;
									}

									// If we got here, then the character is not valid
									valid = false;
									break;
								}
								uint32_t toAcctID = 0;
								if( valid )
								{
									std::istringstream istr(toAcct);
									istr >> toAcctID;
								}

								if( valid )
								{
									if ( db.TransferFunds( userHandle, fromAcctID, toAcctID, amt ) )
									{
										std::cout << "Transfer completed successfully." << std::endl;
									}
									else
									{
										std::cout << "Transfer failed." << std::endl;
									}
								}
								else
								{
									std::cout << "ERROR: Invalid transfer options. Please try again." << std::endl;
								}
							}
							break;

							// Logout
							case 3 :
								db.EndUserSession( userHandle );
								break;

							default :
								std::cout << "ERROR: Invalid selection." << std::endl;
								break;
						}
					}while( selection != 3 );

					selection = 0;
				}
				else
				{
					if( db.UserLockedOut( username ) )
					{
						std::cout << "ERROR: Account has been locked out. Please contact customer service to unlock." << std::endl;
					}
					else
					{
						std::cout << "ERROR: Invalid username and/or password." << std::endl;
					}
				}
			}
			break;

			default:
				std::cout << "ERROR: Invalid menu selection." << std::endl << std::endl;
				break;
		}

	}while( selection != -1 );

	return 0;
}

